//==============================================================================
// SequenceHash.hh
// ----------------------------------------------------------------------------
// Classes that implement hash functions, hash maps, etc. of Sequence 
// objects.  
//
//------------------------------------------------------------------------------
// $Id: $
//------------------------------------------------------------------------------
// $Log: $
//
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#include "LocalSTL.hh"
#include "Sequence.hh"

#ifndef _SEQUENCEHASH
#define _SEQUENCEHASH

//-------------------------------------------
// * eqSeq
//-------------------------------------------
// Functor to compare two sequences for equality.  
//
class eqSeq{
public:
  bool operator()(const Sequence &s1,const Sequence &s2) const {
	 if (s1.size()!= s2.size()) return(false);
	 
	 register const int ssize = s1.size();
	 for(register int i = 0;i< ssize;i++){
		if (s1[i]!=s2[i]) return(false);
	 }
	 return(true);
  }
};

//-------------------------------------------
// * BasicSequenceHash
//-------------------------------------------
// Functor to generate hash function given a sequence.  
// This hash is stolen from SGI stl_hash.h  No special 
// thought has been put into it for DNA sequences, but it 
// seems to work fine. 
//
class BasicSequenceHashF{
public:
  inline size_t operator()(const Sequence &Seq) const {
	 register unsigned long h = 0;
	 register int ssize = Seq.size();
	 for(register int i = 0;i< ssize;i++){
		h = 5 * h + Seq[i];
	 }
	 return((size_t)h);
  }
};




//-------------------------------------------
// * BasicSequenceHash2
//-------------------------------------------
// Functor to generate hash function given a sequence.  
// For testing, I'm just using the built-in hash function for 
// strings.  Later I will replace this with a separate hash 
// function.  
//
class BasicSequenceHashF2{
public:
  size_t operator()(const Sequence &Seq) const {
   char *tempCString = new char[1500];
	Sequence s = Seq;
   s.CopyToCString(tempCString);
	hash<const char*> h;
	size_t rval = h(tempCString);
	delete tempCString;
	return(rval);
  }
};


//typedef hash_set<Sequence,SequenceHash,eqSeq> SeqHashSet;

//  format for hash_map<key,value,hashF,equalKey>


// Should probably make Value a template parameter
//template<class HashF,Value>>
//class BasicSequenceHashMap: public hash_map<Sequence,Value,HashF,eqSeq>{
//public:

//------------------------------------------------------------------------------
// * BasicSequenceHashSet
//------------------------------------------------------------------------------
// A HashSet of sequences.  It is implemented as a template class to 
// make it easy to substitute different hash functors.      
//
template<class T>
class BasicSequenceHashSet: public hash_set<Sequence,T,eqSeq>{
public:


  //-------------------------------------------
  // * Contains
  //-------------------------------------------
  //
  bool Contains(const Sequence &seq)				
  {
	 // KJD This funny "implicit typename not allowed" error started showing up in gcc 3.1
	 // KJD I'm not sure what the typename keyword does but it makes the error go away. 
	 // KJD Trying to typedef this doesn't help.  I'm told, but haven't tried, 
	 // KJD that a typedef like this works:
	 // KJD typedef typename BasicSequenceHashSet::const_iterator BasicSequenceHashSetIterator;
	 // KJD
	 // KJD Where the typename keyword is required.  Go figure. 
	 // KJD 
	 // KJD Apparently the typename keyword is only used in template definitions. 
	 // KJD 
	 typename BasicSequenceHashSet::const_iterator it;
	 // BasicSequenceHashSetIterator it;

	 it = (*this).find(seq);
	 
	 if (it != (*this).end()) {
		return(true);
	 }
	 return(false);
  }
};

// Define a default hash function for a default SequenceHashSet
typedef BasicSequenceHashSet<BasicSequenceHashF> SequenceHashSet;

//hash_map<const char*, int, hash<const char*>, eqstr> StatHash;


// SequenceHashMap  Map;
// do{
//  if (!Map.Contains(Seq)){  
//      Map[Seq] = value;
//  }else{
//     Do something when the particular sequence is already in the hash.
//     depends on application. 
//  }
// while(! end of sequences);


//------------------------------------------------------------------------------
// * BasicSequenceHashMap
//------------------------------------------------------------------------------
// A HashMap of sequences.  It is implemented as a template class to 
// make it easy to substitute different hash functors.  A hash map stores 
// a type of pair, so each entry has a key and a value. 
//
template<class T>
class BasicSequenceHashMap: public hash_map<Sequence,int,T,eqSeq>{
public:

  // bool Lookup(Sequence key,int &value){
  // cout<<"Lookup: Totally bogus.  key is Sequence.  Value is integer."<<endl;
  // const BasicSequenceHashMap::iterator it = find(key);
  // if (it != end()){
  // 	value = (*it).second;
  // 	return(true);
  // }
  // return(false);
  //}
  
  //bool Add(int value,Sequence &key){
  //	 insert(BasicSequenceHashMap::value_type(key,value));
  // }

  //-------------------------------------------
  // * Contains
  //-------------------------------------------
  // Returns true if Seq is in the given map. 
  bool Contains(const Sequence &seq)				
  {
	 typename BasicSequenceHashMap::const_iterator it;
	 it = (*this).find(seq);
	 
	 if (it != (*this).end()) {
		return(true);
	 }
	 return(false);
  }

  //-------------------------------------------
  // * Contains
  //-------------------------------------------
  // Returns true if Seq is in the given map. 
  bool Contains(const Sequence &seq, int &value)				
  {
	 typename BasicSequenceHashMap::const_iterator it;
	 it = (*this).find(seq);
	 if (it != (*this).end()) {
		value = (*it).second;
		return(true);
	 }
	 return(false);
  }

};


typedef BasicSequenceHashMap<BasicSequenceHashF> SequenceHashMap;


// SequenceHashMap  Map;
// do{
//  if (!Map.Contains(Seq)){  
//      Map[Seq] = value;
//  }else{
//     Do something when the particular sequence is already in the hash.
//     depends on application. 
//  }
// while(! end of sequences);


#endif











